package com.scut.chenlujie.library.clink.sample.server;

import com.scut.chenlujie.library.clink.box.StringReceivePacket;
import com.scut.chenlujie.library.clink.core.Connector;
import com.scut.chenlujie.library.clink.core.ScheduleJob;
import com.scut.chenlujie.library.clink.core.schedule.IdleTimeoutScheduleJob;
import com.scut.chenlujie.library.clink.sample.foo.foo;
import com.scut.chenlujie.library.clink.sample.foo.handle.ConnectorCloseChain;
import com.scut.chenlujie.library.clink.sample.foo.handle.ConnectorStringPacketChain;
import com.scut.chenlujie.library.clink.sample.foo.handle.ConnectorHandler;

import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class TCPServer implements  ServerAcceptor.AcceptListener,Group.GroupMessageAdapter {
    private final int port;
    //主监听线程
    private final List<ConnectorHandler> connectorHandlerList = new ArrayList<>();
    private final Map<String , Group> groups = new HashMap<>();
    private final File cachePath;
    private ServerAcceptor acceptor;
    private final ServerStatistics statistics = new ServerStatistics();


    public TCPServer(int port, File cachePath) {
        this.cachePath = cachePath;
        this.port = port;
        this.groups.put(foo.DEFAULT_GROUP_NAME , new Group(foo.DEFAULT_GROUP_NAME ,  this));
        //转发线程池
    }

    public boolean start() {
        try {
            ServerAcceptor serverAcceptor = new ServerAcceptor(this);
            ServerSocketChannel server = ServerSocketChannel.open();
            // 设置为非阻塞
            server.configureBlocking(false);
            // 绑定本地端口
            server.socket().bind(new InetSocketAddress(port));
            // 注册客户端连接到达监听
            server.register(serverAcceptor.getSelector(), SelectionKey.OP_ACCEPT);

            // 启动客户端监听
           this.acceptor = serverAcceptor;
            //开始监听了之后就注册了读写事件，并开始监听读写事件的线程
            serverAcceptor.start();
            if (serverAcceptor.awaitRunning()) {
                System.out.println("服务器准备就绪");
                System.out.println("服务器信息：" + server.getLocalAddress().toString());
                return true;
            } else {
                System.out.println("启动异常！");
                return false;
            }

        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    public void stop() {
        if (acceptor != null) {
            acceptor.exit();
        }

        ConnectorHandler[] connectorHandlers;
        synchronized (connectorHandlerList){
            connectorHandlers = connectorHandlerList.toArray(new ConnectorHandler[0]);
            connectorHandlerList.clear();
        }
        for (ConnectorHandler connectorHandler : connectorHandlers) {
            //exit里面有回调去移除clientHandler的方法，但是clientHandlerList在遍历的时候是不能移除的，会报错
            connectorHandler.exit();
        }


    }

    //主线程每次send都是广播，通过每个不同socket的outputstream发出去
    void broadcast(String str) {
        System.out.println("系统通知："+str);
        ConnectorHandler[] connectorHandlers;
        synchronized (connectorHandlerList){
            connectorHandlers = connectorHandlerList.toArray(new ConnectorHandler[0]);
        }
        for (ConnectorHandler connectorHandler : connectorHandlers) {
            //exit里面有回调去移除clientHandler的方法，但是clientHandlerList在遍历的时候是不能移除的，会报错
            sendMessageToClient(connectorHandler,str);
        }

    }

    @Override
    public void sendMessageToClient(ConnectorHandler handler , String msg){
        handler.send(msg);
        statistics.sendSize++;
    }

    //获取当前状态信息
    public Object[] getStatusString() {
        return new String[]{
                "客户端数量:" + connectorHandlerList.size() ,
                "发送数量：" + statistics.sendSize ,
                "接收数量：" + statistics.receiveSize
        };
    }


    @Override
    public void onNewSocketArrived(SocketChannel channel) {
        try {
            ConnectorHandler connectorHandler = new ConnectorHandler(channel , cachePath);
            System.out.println(connectorHandler.getInfo()+"connected!");
            //构建责任链模式
            connectorHandler.getStringPacketChain()
                    .appendLast(statistics.staticsChain())
                    .appendLast(new ParseCommandConnectorStringPacketChain());
            connectorHandler.getCloseChain()
                    .appendLast(new RemoveQueueOnConnectorClosedChain());

            ScheduleJob scheduleJob = new IdleTimeoutScheduleJob(20 , TimeUnit.SECONDS , connectorHandler);
            connectorHandler.schedule(scheduleJob);

            synchronized (connectorHandlerList){
                connectorHandlerList.add(connectorHandler);
                System.out.println("当前客户端的数量："+ connectorHandlerList.size());
            }

        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("客户端连接异常："+ e.getMessage());
        }
    }

    private class RemoveQueueOnConnectorClosedChain extends ConnectorCloseChain{

        @Override
        protected boolean consume(ConnectorHandler handler, Connector connector) {
            synchronized (connectorHandlerList){
                connectorHandlerList.remove(handler);
                Group group = groups.get(foo.DEFAULT_GROUP_NAME);
                group.removeMember(handler);
            }

            return true;
        }
    }

    private class ParseCommandConnectorStringPacketChain extends ConnectorStringPacketChain{

        @Override
        protected boolean consume(ConnectorHandler handler, StringReceivePacket stringReceivePacket) {
            String str = stringReceivePacket.entity();
            if(str.startsWith(foo.COMMAND_GROUP_JOIN)){
                Group group = groups.get(foo.DEFAULT_GROUP_NAME);
                if(group.addMember(handler)){
                    sendMessageToClient(handler , "Join Group :" + group.getName());
                }
                return true;
            }else if(str.startsWith(foo.COMMAND_GROUP_LEAVE)){
                Group group = groups.get(foo.DEFAULT_GROUP_NAME);
                if(group.removeMember(handler)){
                    sendMessageToClient(handler , "leave Group :" + group.getName());
                }
                return true;
            }
            return false;
        }

        @Override
        protected boolean consumeAgain(ConnectorHandler handler , StringReceivePacket packet){
            //捡漏模式，当我们第一遍未消费，然后又没有加入到群，自然没有后续节点的消费
            //此时我们进行二次消费，返回发送过来的消息
            sendMessageToClient(handler , packet.entity());
            return true;
        }
    }




}
